package com.hzlj.position.locate.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.fz.common.base.core.DistanceUtils;
import com.fz.common.base.core.JsonUtils;
import com.fz.common.base.core.RequestUtil;
import com.fz.common.base.exception.PubException;
import com.fz.common.dict.service.DictionaryService;
import com.hzlj.position.config.cache.JzJbxxConfigCache;
import com.hzlj.position.config.cache.JzJbxxDeviceBindCache;
import com.hzlj.position.config.common.dto.common.PositionAddDTO;
import com.hzlj.position.config.common.dto.common.ReportLocateDTO;
import com.hzlj.position.config.common.dto.jzJbxxConfig.JzJbxxConfigQueryResultDTO;
import com.hzlj.position.config.common.dto.jzJbxxDeviceBind.JzJbxxDeviceBindCacheDTO;
import com.hzlj.position.config.common.enums.WarningType;
import com.hzlj.position.config.config.PositionConfig;
import com.hzlj.position.locate.common.dto.position.CrossAbnResultDTO;
import com.hzlj.position.locate.common.dto.position.PositionAddResultDTO;
import com.hzlj.position.locate.common.dto.position.PositionExtDTO;
import com.hzlj.position.locate.common.dto.position.PositionQueryResultDTO;
import com.hzlj.position.locate.common.enums.AreaOutType;
import com.hzlj.position.locate.common.enums.PositionSysCheck;
import com.hzlj.position.locate.common.model.Position;
import com.hzlj.position.locate.service.PositionAddTaskService;
import com.hzlj.position.locate.service.ReportInspectionCorrectService;
import com.hzlj.sqjz.config.common.enums.HandleStatus;
import com.hzlj.sqjz.jz.cache.JzJbxxCache;
import com.hzlj.sqjz.jz.common.dto.common.JzJbxxCacheDTO;
import com.hzlj.sqjz.jz.service.JzYcService;
import com.hzlj.sqjz.lc.common.dto.lcWc.LcWcQueryResultDTO;
import com.hzlj.sqjz.lc.service.LcWcService;
import com.hzlj.sqjz.system.cache.JgCache;
import com.hzlj.sqjz.system.cache.XzqhBjCache;
import com.hzlj.sqjz.system.common.dto.jg.JgXzqhDTO;
import com.hzlj.sqjz.system.common.dto.xzqh.XzqhQueryResultDTO;
import com.hzlj.sqjz.system.common.dto.xzqhBj.XzqhBjQueryResultDTO;
import com.hzlj.sqjz.system.service.XzqhService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.hzlj.position.config.common.constant.Topic.POSITION_ADD;
import static com.hzlj.position.config.config.IdConfig.POSITION_ID_GEN;


/**
 * @author lifh
 * @date 2022/9/30 11:00
 **/
@Slf4j
@Service
public class PositionAddTaskTaskServiceImpl implements PositionAddTaskService {
    @Resource
    private JzJbxxDeviceBindCache jzJbxxDeviceBindCache;
    @Resource
    private JzJbxxCache jzJbxxCache;
    @Resource
    private JzJbxxConfigCache jzJbxxConfigCache;
    @Resource
    private JgCache baseJgCache;
    @Resource
    private PositionConfig positionConfig;
    @Resource
    private XzqhBjCache xzqhBjCache;
    @Resource
    private XzqhService xzqhService;
    @Resource
    private LcWcService lcWcService;
    @Resource
    private JzYcService ycService;
    @Resource
    private ReportInspectionCorrectService reportInspectionCorrectService;
    @Resource
    private KafkaTemplate<String, Position> kafkaTemplate;
    @Resource
    private DictionaryService dictionaryService;


    @Override
    public PositionAddResultDTO add(PositionAddDTO add) {
        if (ObjectUtil.isNull(add)) {
            return PositionAddResultDTO.fail("定位数据为空");
        }
        if (log.isDebugEnabled()) {
            log.debug("收到上报位置数据:{}", JsonUtils.obj2json(add));
        }
        Position position = BeanUtil.copyProperties(add, Position.class);
        //校验
        String errMsg = this.verify(position);
        if (ObjectUtil.isNotEmpty(errMsg)) {
            return PositionAddResultDTO.fail(errMsg);
        }
        //填充参数
        PositionAddResultDTO result = this.fillBasic(position);
        if (!result.isSuccess()) {
            return result;
        }

        try {
            //位置纠偏(会修改位置信息)
            reportInspectionCorrectService.correct(position);

            //设置 出省，出市，出区 状态
            if (!isLocateFail(position)) {
                setAreaOutType(position);
            }
            //设置越界+请假
            if (!isLocateFail(position)) {
                setCrossStatus(position);
            }
            //低电
            if (!isLocateFail(position)) {
                setElectricStatus(position);
            }

            //处理状态
            setHandleStatusAndWarning(position);

            //添加队列
            kafkaTemplate.send(POSITION_ADD, position.getId(), position);
        } catch (Exception e) {
            log.error("【定位数据】添加任务异常 ,position={}", JsonUtils.obj2json(add), e);
            return PositionAddResultDTO.fail("初始化数据异常，请联系工作人员操作");
        }
        //腕带厂商需要
        result.addData(position.getId());

        if (Boolean.TRUE.equals(add.getReturnPosition())) {
            result.setPosition(BeanUtil.copyProperties(position, PositionQueryResultDTO.class));
        }

        return result;
    }

    @Override
    public PositionQueryResultDTO add(ReportLocateDTO reportLocate) {
        PositionAddDTO position = new PositionAddDTO();
        position.setId(POSITION_ID_GEN.nextIdStr());
        position.setExternalDataId(reportLocate.getId());
        position.setLongitude(reportLocate.getLongitude());
        position.setLatitude(reportLocate.getLatitude());
        position.setPosition(reportLocate.getReportAddress());
        position.setPositionTime(reportLocate.getReportTime());
        position.setDeviceCode(reportLocate.getDeviceCode());
        position.setChannelType(reportLocate.getChannelType());
        position.setChannel(reportLocate.getChannel());
        position.setReportType(reportLocate.getReportType());
        position.setWarningType(WarningType.SUCCESS.getCode());
        position.setPositionExt(reportLocate.getPositionExt());
        position.setDataType(reportLocate.getDataType());
        if(ObjectUtil.isNotEmpty(reportLocate.getDataType())){
            position.setSysCheck(PositionSysCheck.ING.getCheck());
        }
        position.setReturnPosition(true);
        PositionAddResultDTO positionResult = this.add(position);
        if (!positionResult.isSuccess()) {
            throw new PubException(positionResult.getMsg());
        }
        return positionResult.getPosition();
    }


    private void setCrossStatus(Position position) {
        CrossAbnResultDTO abn = this.isCrossWithMore(position.getJzId(), position.getJgCode(), position.getLongitude(), position.getLatitude());
        //请假状态
        position.setLeaving(abn.getLeaving());
        //越界
        if (abn.isCross()) {
            position.setWarningType(WarningType.CROSS.getCode());
            //请假中
            if (Boolean.TRUE.equals(position.getLeaving())) {
                position.setWarningType(WarningType.CROSS_LEAVING.getCode());
            }
        }
        //设置ext
        if (abn.checkNull()) {
            return;
        }
        PositionExtDTO positionExt = BeanUtil.copyProperties(abn, PositionExtDTO.class);
        PositionExtDTO inputPositionExt = position.getPositionExt();
        if (ObjectUtil.isEmpty(inputPositionExt)) {
            position.setPositionExt(positionExt);
        } else {
            BeanUtil.copyProperties(positionExt, inputPositionExt, CopyOptions.create().ignoreNullValue());
        }
    }

    /**
     * 1,查询是否配置了边界，如果没有配置则不算越界
     * 2，在禁止区域算越界，允许区域不算越界
     * 3，越界区域正好在请假目的地，则不算越界
     */
    public CrossAbnResultDTO isCrossWithMore(String jzId,
                                             String jgCode,
                                             String longitude,
                                             String latitude) {
        CrossAbnResultDTO abn = new CrossAbnResultDTO();

        //查询配置
        JzJbxxConfigQueryResultDTO jzJbxxConfig = jzJbxxConfigCache.getJzJbxxConfigByJzId(jzId);
        if (jzJbxxConfig == null
                || (ObjectUtil.isEmpty(jzJbxxConfig.getAllowXzqhIds()) && ObjectUtil.isEmpty(jzJbxxConfig.getForbitXzqhIds()))) {
            return abn;
        }

        //可越界距离
        abn.setCrossDistance(jzJbxxConfig.getCrossDistance());

        //优先判断禁止区域，只要在禁止区域，则提示越界
        boolean cross = false;
        if (ObjectUtil.isNotEmpty(jzJbxxConfig.getForbitXzqhIds())) {
            cross = Arrays.stream(jzJbxxConfig.getForbitXzqhIds().split(",")).filter(ObjectUtil::isNotEmpty)
                    .anyMatch(xzqhId -> isWithinArea(xzqhId, longitude, latitude));
        }

        //如果没在禁止区域，检查是否在在其中一个允许区域，没有则提示越界（没有配置不算越界）
        if (!cross && ObjectUtil.isNotEmpty(jzJbxxConfig.getAllowXzqhIds())) {
            //如果配置的值无效，则也不算越界
            List<List<XzqhBjQueryResultDTO>> bjs = Arrays.stream(jzJbxxConfig.getAllowXzqhIds().split(",")).filter(ObjectUtil::isNotEmpty)
                    .map(xzqhId -> xzqhBjCache.getByXzqhId(xzqhId)).filter(ObjectUtil::isNotEmpty)
                    .collect(Collectors.toList());
            if (ObjectUtil.isNotEmpty(bjs)) {
                cross = bjs.stream().noneMatch(xzqhId -> isWithinArea(xzqhId, longitude, latitude, jzJbxxConfig.getCrossDistance()));
            }
        }

        if (!cross) {
            return abn;
        }

        //设置数据
        abn.setAllowXzqhIds(jzJbxxConfig.getAllowXzqhIds());
        abn.setForbitXzqhIds(jzJbxxConfig.getForbitXzqhIds());
        abn.setCross(true);

        //强制措施
        Boolean qzcs = ycService.isJzYc4Qzcsing(jzId);
        abn.setQzcs(qzcs);
        if (qzcs) {
            abn.setCross(false);
            return abn;
        }

        //请假+跨市县
        List<LcWcQueryResultDTO> lcs = lcWcService.listLcWc4Leaving(jzId);
        if (ObjectUtil.isEmpty(lcs)) {
            return abn;
        }
        //目的地
        LcWcQueryResultDTO lc = lcs.get(0);
        abn.setLeaving(true);
        abn.setLeaveId(lc.getId());
        abn.setLeaveType(lc.getLclx());
        abn.setLeaveKsRq(DateUtil.formatDate(lc.getSqksrq()));
        abn.setLeaveJsRq(DateUtil.formatDate(lc.getSqjsrq()));
        //目的地边界ID
        List<String> mddXzqhIds = lcs.stream().map(LcWcQueryResultDTO::getMddXzqhIds).filter(ObjectUtil::isNotEmpty)
                .flatMap(e -> Arrays.stream(e.split(","))).filter(ObjectUtil::isNotEmpty).distinct()
                .collect(Collectors.toList());
        if (ObjectUtil.isNotEmpty(mddXzqhIds)) {
            abn.setLeaveMddXzqhIds(String.join(",", mddXzqhIds));
            abn.setLeaveMddXzqhMcs(mddXzqhIds.stream()
                    .map(xzqhService::getXzqhById).filter(ObjectUtil::isNotEmpty)
                    .map(XzqhQueryResultDTO::getXzqhMc).collect(Collectors.joining(","))
            );
        }

        //在请假中则不算越界
        String[] ignoreCrossInLeaveJgCodes = positionConfig.getIgnoreCrossInLeaveJgCodes();
        if (ObjectUtil.isNotEmpty(ignoreCrossInLeaveJgCodes)
                && Arrays.stream(ignoreCrossInLeaveJgCodes).anyMatch(jgCode::startsWith)) {
            abn.setCross(false);
            return abn;
        }

        //在请假的范围内
        boolean inLeaveBj = mddXzqhIds.stream()
                .anyMatch(xzqhId -> isWithinArea(xzqhId, longitude, latitude, positionConfig.getLeavingCrossDistance()));
        if (inLeaveBj) {
            abn.setCross(false);
        }

        return abn;
    }


    /**
     * 设置处理状态+告警状态
     */
    private void setHandleStatusAndWarning(Position position) {
        Boolean warning = position.getWarning();
        Boolean needHandle;
        String needHandleErrorCodes = "";

        if (ObjectUtil.isNotEmpty(warning)) {
            needHandle = Boolean.TRUE.equals(warning);
        } else {
            //warning状态
            warning = dictionaryService.getByConfigKey(
                    RequestUtil.getAppId(), "LOCATE_WARNING_TYPE", position.getWarningType(), "warning", Boolean.class
            );
            //处理状态
            needHandle = dictionaryService.getByConfigKey(
                    RequestUtil.getAppId(), "LOCATE_WARNING_TYPE", position.getWarningType(), "handle", Boolean.class
            );
            //需要处理的errorCodes
            needHandleErrorCodes = dictionaryService.getByConfigKey(
                    RequestUtil.getAppId(), "LOCATE_WARNING_TYPE", position.getWarningType(), "handleErrorCodes", String.class
            );
        }


        //设置状态
        position.setWarning(Boolean.TRUE.equals(warning));
        if (Boolean.TRUE.equals(needHandle)
                && (ObjectUtil.isEmpty(needHandleErrorCodes)
                || Arrays.stream(needHandleErrorCodes.split(",")).anyMatch(e -> position.getPosition().contains(e)))) {
            position.setHandleStatus(HandleStatus.WAIT.getStatus());
        } else {
            position.setHandleStatus(HandleStatus.NONE.getStatus());
        }
    }


    /**
     * 设置低电状态
     */
    private void setElectricStatus(Position position) {
        PositionExtDTO positionExt = position.getPositionExt();
        if (position.getWarningType().equals(WarningType.SUCCESS.getCode())
                && ObjectUtil.isNotEmpty(positionExt)
                && ObjectUtil.isNotEmpty(positionExt.getElectricValue())
                && positionExt.getElectricValue() <= positionConfig.getLowBat()) {
            position.setWarningType(WarningType.LOWER_POWER.getCode());
        }
    }

    /**
     * 设置 出省，出市，出区 状态
     */
    private void setAreaOutType(Position position) {
        List<JgXzqhDTO> xtJgXzqhs = baseJgCache.getJgXzqh(position.getJgCode());
        if (ObjectUtil.isEmpty(xtJgXzqhs)) {
            return;
        }

        for (JgXzqhDTO xzqh : xtJgXzqhs) {
            Map<String, String> areaOutTypes = positionConfig.getAreaOutTypes();
            if (!areaOutTypes.containsKey(xzqh.getJgLscj())) {
                continue;
            }
            boolean withinArea = isWithinArea(xzqh.getXzqhId(), position.getLongitude(), position.getLatitude());
            if (!withinArea) {
                position.setAreaOutType(areaOutTypes.get(xzqh.getJgLscj()));
                return;
            }
        }
    }

    public boolean isLocateFail(Position position) {
        return ObjectUtil.isEmpty(position.getLatitude())
                || ObjectUtil.isEmpty(position.getLongitude())
                || !WarningType.SUCCESS.getCode().equals(position.getWarningType());
    }


    private boolean isWithinArea(String xzqhId, String lng, String lat) {
        return isWithinArea(xzqhId, lng, lat, BigDecimal.ZERO);
    }

    private boolean isWithinArea(String xzqhId, String lng, String lat, BigDecimal distance) {
        if (ObjectUtil.isEmpty(xzqhId)) {
            return false;
        }
        return isWithinArea(xzqhBjCache.getByXzqhId(xzqhId), lng, lat, distance);
    }

    /**
     * 是否在边界里(只要是任一一个都行)
     * 如果没有设置边界，或者 经纬度存在空值，则返回空
     * sureDistanceMeter:单位米
     */
    private boolean isWithinArea(List<XzqhBjQueryResultDTO> bjs, String lng, String lat, BigDecimal distance) {
        if (ObjectUtil.isEmpty(lng) || ObjectUtil.isEmpty(lat)) {
            return false;
        }
        if (ObjectUtil.isEmpty(bjs)) {
            return false;
        }
        return bjs.stream().anyMatch(bj ->
                DistanceUtils.isWithinArea(
                        Double.parseDouble(lng),
                        Double.parseDouble(lat),
                        bj.getBjjwd(),
                        distance == null ? BigDecimal.ZERO.doubleValue() : distance.multiply(BigDecimal.valueOf(1000)).doubleValue()
                ));
    }


    private PositionAddResultDTO fillBasic(Position position) {
        //设置channelType
        JzJbxxDeviceBindCacheDTO deviceBindCache
                = jzJbxxDeviceBindCache.getJzJbxxDeviceBindCache(position.getDeviceCode(), position.getChannel());

        if (ObjectUtil.isEmpty(deviceBindCache)) {
            log.warn("【定位数据】设备暂未绑定，请联系工作人员操作：deviceCode={},channel={}", position.getDeviceCode(), position.getChannel());
            return PositionAddResultDTO.fail("设备暂未绑定，请联系工作人员操作");
        }

        //填充参数
        Date nowTime = new Date();
        if (ObjectUtil.isEmpty(position.getId())) {
            position.setId(POSITION_ID_GEN.nextIdStr());
        }
        position.setCreateTime(nowTime);
        position.setUpdateTime(nowTime);
        position.setJzId(deviceBindCache.getJzId());
        position.setChannelType(deviceBindCache.getChannelType());
        position.setCreateTime(new Date());
        position.setHandleStatus(HandleStatus.NONE.getStatus());

        //设置用户信息
        JzJbxxCacheDTO jzry = jzJbxxCache.getJzJbxxByJzId(position.getJzId());
        if (ObjectUtil.isEmpty(jzry)) {
            log.warn("【定位数据】没有有效的用户信息，请核实是否有误:jzId={},deviceCode={},channel={}",
                    position.getJzId(), position.getDeviceCode(), position.getChannel());
            return PositionAddResultDTO.fail("没有有效的用户信息，请联系工作人员操作");
        }

        //基本信息
        position.setXm(jzry.getXm());
        position.setJgCode(jzry.getJgCode());
        position.setJgMc(jzry.getJgMc());

        //状态初始化
        position.setAreaOutType(AreaOutType.NONE.getCode());
        position.setLeaving(false);

        //时间格式化，防止数据库做四舍五入
        position.setPositionTime(
                DateUtil.parseDateTime(DateUtil.formatDateTime(position.getPositionTime()))
        );

        return PositionAddResultDTO.success("数据上报成功");
    }

    /**
     * 校验参数
     */
    private String verify(Position position) {
        if (StrUtil.isEmpty(position.getDeviceCode())) {
            return "设备编号[deviceCode]不能为空";
        }
        if (StrUtil.isEmpty(position.getChannel())) {
            return "渠道编号[channel]不能为空";
        }
        if (StrUtil.isEmpty(position.getWarningType())) {
            return "定位状态[warningType]不能为空";
        }
        if (WarningType.SUCCESS.getCode().equals(position.getWarningType())) {
            if (StrUtil.isEmpty(position.getLongitude())) {
                return "经度[longitude]不能为空";
            }
            if (StrUtil.isEmpty(position.getLatitude())) {
                return "纬度[latitude]不能为空";
            }
            if (StrUtil.isEmpty(position.getPosition())) {
                return "位置描述[position]不能为空";
            }
        }
        if (position.getPositionTime() == null) {
            return "定位时间[positionTime]不能为空";
        }
        return null;
    }

    public static void main(String[] args) {
        boolean withinArea = DistanceUtils.isWithinArea(
                Double.parseDouble("117.664368"),
                Double.parseDouble("31.269343"),
                "117.853268,31.489494;117.855986,31.490525;117.857047,31.490726;117.857669,31.490566;117.858376,31.489701;117.858906,31.489171;117.859552,31.489096;117.860128,31.489380;117.860766,31.489949;117.861696,31.490866;117.864242,31.492307;117.867589,31.493280;117.872041,31.494788;117.876091,31.496396;117.878065,31.497566;117.882147,31.500342;117.883418,31.500878;117.884991,31.501314;117.889908,31.501749;117.892817,31.502585;117.896195,31.504156;117.898903,31.505225;117.900473,31.505693;117.901677,31.505859;117.902676,31.505627;117.907761,31.505541;117.912569,31.504541;117.915467,31.502429;117.917559,31.500558;117.920718,31.497983;117.923069,31.495421;117.924776,31.494530;117.925129,31.494045;117.926395,31.492665;117.928996,31.490707;117.931062,31.490123;117.933740,31.489652;117.935746,31.489529;117.938088,31.489692;117.940300,31.489964;117.942977,31.491097;117.944320,31.492178;117.950696,31.495873;117.953313,31.497521;117.955723,31.498712;117.958408,31.499845;117.960099,31.500303;117.959045,31.496617;117.958329,31.495628;117.958695,31.495035;117.958348,31.491600;117.957740,31.488633;117.959562,31.486081;117.964362,31.485538;117.969161,31.484307;117.973136,31.482405;117.976574,31.480510;117.978943,31.478635;117.981564,31.476527;117.983118,31.473980;117.981729,31.472170;117.977398,31.470413;117.974950,31.468852;117.970125,31.468476;117.967981,31.468515;117.963083,31.467739;117.964043,31.457796;117.970749,31.450274;117.970905,31.447303;117.969034,31.444182;117.969347,31.439647;117.974336,31.434944;117.977611,31.434309;117.981353,31.436330;117.983066,31.440076;117.985873,31.440538;118.010942,31.434782;118.022430,31.432147;118.110609,31.412113;118.107149,31.404565;118.107324,31.401892;118.107109,31.397863;118.107664,31.395335;118.111449,31.393398;118.109430,31.389112;118.108696,31.386401;118.107797,31.385339;118.107282,31.384789;118.106938,31.382115;118.108525,31.381127;118.108354,31.376439;118.111964,31.376733;118.114058,31.376842;118.118070,31.376923;118.118669,31.376592;118.118911,31.375060;118.119016,31.374396;118.118630,31.369194;118.118328,31.368827;118.118415,31.364210;118.119014,31.364285;118.117983,31.356077;118.117340,31.355967;118.117212,31.355234;118.116435,31.354903;118.116435,31.353584;118.118028,31.353586;118.117985,31.352523;118.117426,31.351754;118.117295,31.350800;118.123228,31.348608;118.124001,31.349926;118.126876,31.348620;118.128989,31.347662;118.128989,31.346856;118.131140,31.345393;118.130365,31.344586;118.130905,31.343132;118.130279,31.341729;118.128645,31.342020;118.128479,31.339125;118.128263,31.338465;118.124517,31.335272;118.120390,31.334828;118.119703,31.335853;118.119150,31.335341;118.118934,31.333838;118.118118,31.331198;118.117037,31.328961;118.118499,31.325152;118.117382,31.325003;118.116781,31.323391;118.115319,31.322508;118.115834,31.321630;118.114632,31.321336;118.115750,31.319505;118.116437,31.318186;118.113597,31.317526;118.113169,31.318309;118.112739,31.319335;118.112309,31.320288;118.111707,31.320874;118.110160,31.320946;118.107840,31.320797;118.106466,31.320870;118.105176,31.321090;118.103888,31.321015;118.102341,31.321161;118.100536,31.320868;118.099334,31.321160;118.098131,31.321820;118.096929,31.321820;118.095898,31.321965;118.094696,31.321892;118.093236,31.321746;118.092206,31.321379;118.090917,31.321159;118.089973,31.320720;118.089801,31.320280;118.089544,31.319620;118.088943,31.319913;118.087998,31.319473;118.086796,31.319181;118.086024,31.318815;118.085938,31.318595;118.085938,31.317862;118.085851,31.317496;118.085166,31.317422;118.084479,31.317202;118.083106,31.317203;118.081217,31.316984;118.079329,31.317059;118.078043,31.316913;118.075725,31.316841;118.073924,31.316769;118.072552,31.316770;118.071008,31.316186;118.070064,31.315820;118.068863,31.315308;118.067234,31.314796;118.066719,31.313991;118.066119,31.313112;118.065262,31.312454;118.064062,31.311795;118.063462,31.311062;118.062604,31.310331;118.061661,31.309452;118.060718,31.307986;118.059175,31.307917;118.057375,31.307551;118.055575,31.307409;118.054289,31.307412;118.051804,31.307856;118.051118,31.307637;118.050348,31.306832;118.050690,31.305659;118.050004,31.305146;118.050088,31.303022;118.048718,31.302293;118.046662,31.300830;118.045976,31.299365;118.041865,31.298201;118.037410,31.297477;118.035183,31.296603;118.029313,31.295123;118.028848,31.295005;118.025252,31.293842;118.023197,31.293114;118.020459,31.290630;118.019260,31.290193;118.018405,31.288435;118.016522,31.286681;118.013270,31.284344;118.012243,31.282294;118.010532,31.281860;118.008306,31.282306;118.006424,31.281138;118.007621,31.280108;118.006766,31.278056;118.007622,31.276588;118.005398,31.274542;118.004028,31.272346;118.001633,31.268834;118.000264,31.265756;117.999751,31.262679;117.997869,31.260044;117.997012,31.259314;117.995130,31.257265;117.994959,31.255212;117.992906,31.253165;117.992392,31.250819;117.991024,31.247450;117.989314,31.243788;117.988288,31.240857;117.989315,31.240560;117.990341,31.242758;117.992737,31.242016;117.993251,31.240255;117.995133,31.238929;117.996331,31.238192;118.000953,31.237004;118.003597,31.236281;118.004204,31.236114;118.004888,31.235819;118.012420,31.233303;118.011051,31.229491;118.009511,31.226415;118.008484,31.223630;118.007286,31.220406;118.006258,31.216887;118.004719,31.213663;118.003522,31.207209;118.002666,31.204277;118.002153,31.198701;118.001640,31.193566;118.001375,31.190376;118.001128,31.187403;118.000786,31.178303;118.001300,31.176100;118.002719,31.174623;117.997537,31.170356;117.995566,31.166037;117.993579,31.161027;117.993466,31.156214;117.993900,31.152310;117.993492,31.146359;117.994178,31.141534;117.995393,31.136468;117.996035,31.130038;117.996695,31.124295;117.996574,31.119256;117.996174,31.113304;117.994724,31.108743;117.992242,31.105346;117.989178,31.100129;117.986417,31.096508;117.984508,31.094480;117.979656,31.092500;117.978301,31.091572;117.976393,31.090265;117.973164,31.088718;117.968034,31.086514;117.962088,31.083181;117.959086,31.080250;117.956117,31.078928;117.953401,31.076911;117.949626,31.075373;117.944783,31.073395;117.940487,31.072093;117.934049,31.070599;117.930290,31.069978;117.926030,31.070051;117.921777,31.070583;117.918612,31.070636;117.904663,31.075154;117.892756,31.080648;117.885221,31.088341;117.880432,31.100900;117.879757,31.111486;117.875078,31.124329;117.864645,31.135410;117.854492,31.140792;117.845461,31.142466;117.826641,31.141355;117.802013,31.131925;117.787643,31.122096;117.775880,31.113624;117.769434,31.107636;117.762079,31.098284;117.746888,31.059842;117.732467,31.026898;117.729045,31.018897;117.725965,31.012121;117.723819,31.012164;117.719689,31.012245;117.717997,31.012279;117.717059,31.012298;117.715603,31.012326;117.714801,31.014160;117.713035,31.019235;117.713349,31.020987;117.712881,31.021299;117.708269,31.021151;117.705656,31.017779;117.702229,31.013520;117.700859,31.013375;117.699143,31.013083;117.698457,31.013820;117.696621,31.012847;117.695372,31.013383;117.694001,31.013238;117.692117,31.012359;117.695031,31.004709;117.694347,31.002945;117.693030,31.002156;117.691630,31.001318;117.688912,30.999044;117.690233,30.997363;117.689376,30.992511;117.688348,30.991190;117.684408,30.991197;117.683209,30.989287;117.680810,30.987526;117.683209,30.986051;117.682353,30.983405;117.678926,30.979881;117.676185,30.976797;117.676699,30.975325;117.677728,30.971058;117.676535,30.971731;117.675761,30.972169;117.674648,30.972392;117.672848,30.972395;117.671136,30.972252;117.669336,30.971961;117.667623,30.971670;117.665484,30.971803;117.661800,30.969548;117.660513,30.968962;117.660513,30.964547;117.661882,30.958366;117.660339,30.958075;117.659484,30.956825;117.658456,30.954767;117.658371,30.952852;117.657326,30.951405;117.656143,30.949766;117.655116,30.949327;117.655125,30.948693;117.655149,30.946931;117.655168,30.945455;117.655185,30.944281;117.655206,30.942813;117.655220,30.941838;117.655168,30.942389;117.654398,30.943262;117.647101,30.951522;117.646000,30.952768;117.646553,30.954503;117.646598,30.954918;117.646426,30.955839;117.646251,30.956490;117.645712,30.956975;117.646045,30.957688;117.644962,30.958216;117.644774,30.958416;117.644956,30.959337;117.645348,30.960000;117.644131,30.960699;117.644332,30.961536;117.642448,30.961860;117.641522,30.962821;117.640040,30.961096;117.640015,30.961660;117.638558,30.962237;117.637589,30.963035;117.637413,30.963343;117.637547,30.963681;117.637568,30.964255;117.637326,30.964973;117.636848,30.965360;117.635925,30.965398;117.635316,30.966396;117.634842,30.966884;117.634742,30.967991;117.634166,30.967745;117.633552,30.967777;117.632501,30.968602;117.631871,30.969248;117.630653,30.969737;117.629144,30.970536;117.628661,30.970954;117.628445,30.971262;117.627921,30.971495;117.621135,30.974515;117.618324,30.974995;117.615582,30.975304;117.611051,30.974963;117.603405,30.977707;117.600324,30.979421;117.595455,30.980074;117.590309,30.980110;117.587299,30.980523;117.584208,30.979152;117.580990,30.976340;117.578247,30.973118;117.576944,30.972534;117.574238,30.971576;117.571321,30.971405;117.567582,30.971269;117.563641,30.970995;117.562270,30.971407;117.560829,30.972299;117.559737,30.973672;117.558192,30.975282;117.555692,30.976587;117.550893,30.976691;117.548662,30.976141;117.547430,30.974908;117.546329,30.971890;117.543760,30.969936;117.542457,30.969628;117.538135,30.969765;117.534950,30.970384;117.532034,30.971106;117.529361,30.972477;117.528007,30.974181;117.527547,30.975974;117.529144,30.985097;117.533024,30.991660;117.533093,30.993333;117.531617,30.994338;117.525524,30.995546;117.517756,30.996819;117.508710,31.002512;117.505160,31.004589;117.502104,31.005671;117.493936,31.021074;117.490603,31.028003;117.488111,31.032161;117.482850,31.034378;117.478414,31.037982;117.477025,31.041310;117.479517,31.044081;117.483675,31.046299;117.488944,31.048517;117.496150,31.049073;117.506679,31.049349;117.509178,31.051013;117.509699,31.053710;117.512225,31.057941;117.514698,31.063955;117.518787,31.068711;117.520775,31.074415;117.522163,31.077603;117.523301,31.081486;117.522293,31.084249;117.521816,31.087235;117.521634,31.091823;117.520627,31.094818;117.518804,31.097365;117.516434,31.099233;117.510906,31.103207;117.508041,31.106685;117.506747,31.108767;117.507060,31.111512;117.508458,31.114702;117.511973,31.117176;117.515983,31.117119;117.519715,31.117068;117.521911,31.120245;117.521972,31.123225;117.522024,31.125972;117.522103,31.129870;117.522440,31.133762;117.523561,31.136497;117.525478,31.139219;117.531406,31.141886;117.537317,31.143867;117.541873,31.144489;117.547081,31.147437;117.549563,31.151395;117.550764,31.151648;117.551930,31.152181;117.553823,31.152775;117.555362,31.152896;117.556347,31.153488;117.556702,31.154826;117.556229,31.156242;117.555952,31.157972;117.556462,31.158953;117.556900,31.160081;117.556835,31.160748;117.556222,31.162266;117.555163,31.163991;117.555173,31.166134;117.555163,31.167690;117.554847,31.169027;117.554729,31.170837;117.554300,31.173395;117.553226,31.174935;117.552529,31.175736;117.550681,31.177253;117.549635,31.178130;117.549534,31.177807;117.549413,31.177162;117.548989,31.177020;117.547878,31.176937;117.547797,31.176656;117.548039,31.175608;117.547979,31.174521;117.548181,31.173479;117.547474,31.172949;117.547449,31.172294;117.547398,31.171361;117.547247,31.170681;117.546793,31.170655;117.546211,31.171183;117.546085,31.171762;117.542429,31.173045;117.541640,31.172886;117.541609,31.172288;117.541893,31.170557;117.541793,31.167023;117.541526,31.166532;117.538549,31.166510;117.537188,31.166455;117.535073,31.166576;117.534379,31.167046;117.534315,31.168148;117.534473,31.169187;117.534157,31.169910;117.533146,31.170128;117.533083,31.170946;117.532515,31.171134;117.531472,31.171163;117.531472,31.173965;117.531853,31.174507;117.532456,31.174278;117.532733,31.174526;117.533398,31.174221;117.533840,31.173845;117.534567,31.174035;117.535420,31.176020;117.535654,31.176661;117.535760,31.176951;117.536145,31.178005;117.535703,31.178161;117.535167,31.178411;117.535483,31.179105;117.535008,31.179418;117.535293,31.180080;117.534883,31.180426;117.534598,31.180551;117.533809,31.180234;117.533271,31.179446;117.532798,31.179035;117.532103,31.178971;117.531219,31.179346;117.530240,31.179816;117.529577,31.180413;117.529671,31.180980;117.530144,31.181673;117.530839,31.181989;117.531187,31.182934;117.531124,31.183281;117.530523,31.183720;117.530934,31.184225;117.532052,31.185158;117.532070,31.186069;117.531715,31.186619;117.531834,31.187209;117.532386,31.187683;117.533063,31.188391;117.533215,31.188551;117.533685,31.189824;117.531146,31.191055;117.530162,31.191874;117.530731,31.193533;117.526287,31.198557;117.524456,31.202420;117.530827,31.205502;117.530699,31.206650;117.534955,31.208190;117.546047,31.213725;117.550413,31.217319;117.551585,31.221202;117.553358,31.224152;117.554090,31.225309;117.556107,31.235496;117.567850,31.250290;117.570098,31.258023;117.569148,31.260836;117.566831,31.273267;117.572984,31.274004;117.576482,31.275101;117.581315,31.276174;117.585342,31.277262;117.589629,31.277428;117.597387,31.278000;117.602533,31.281591;117.603898,31.283438;117.603914,31.283463;117.603939,31.283494;117.606387,31.286808;117.608330,31.289987;117.609719,31.293177;117.611125,31.296364;117.613034,31.298170;117.616550,31.299950;117.621635,31.300561;117.624282,31.298918;117.628561,31.299313;117.631572,31.302706;117.633777,31.305881;117.635460,31.309524;117.637674,31.313159;117.640747,31.319300;117.642421,31.322943;117.644123,31.327958;117.645538,31.331379;117.647247,31.336624;117.648966,31.342329;117.649591,31.346215;117.650771,31.351699;117.652733,31.355796;117.655250,31.361256;117.656674,31.365590;117.658341,31.368316;117.661566,31.374678;117.663143,31.377834;117.665319,31.382421;117.667559,31.387201;117.669503,31.390609;117.671708,31.393556;117.674980,31.396717;117.678826,31.401013;117.684670,31.407193;117.687469,31.409394;117.687904,31.410401;117.688557,31.413749;117.688237,31.415767;117.689669,31.420561;117.690277,31.423531;117.690615,31.427194;117.690945,31.430167;117.691553,31.433593;117.692691,31.436329;117.693802,31.438374;117.694931,31.441340;117.695529,31.444308;117.696398,31.447044;117.697292,31.451387;117.699306,31.458229;117.700166,31.460740;117.703093,31.463728;117.705541,31.466230;117.709513,31.468348;117.712016,31.469653;117.715173,31.469921;117.717541,31.469511;117.720100,31.469073;117.728426,31.466956;117.732186,31.466899;117.735120,31.466395;117.738064,31.466578;117.741311,31.467673;117.743482,31.469244;117.745410,31.471278;117.747311,31.472624;117.751617,31.473704;117.756445,31.473401;117.759362,31.471979;117.761186,31.469658;117.763018,31.468026;117.766247,31.468433;117.767628,31.470245;117.768757,31.472978;117.770199,31.477311;117.771336,31.480274;117.773003,31.483226;117.775720,31.484789;117.779757,31.485642;117.782970,31.485591;117.785922,31.485543;117.790471,31.485473;117.794213,31.484725;117.798215,31.483974;117.801671,31.482774;117.805664,31.481561;117.810222,31.481718;117.814007,31.483493;117.816464,31.485288;117.818912,31.486623;117.821871,31.487719;117.825639,31.488118;117.829927,31.488048;117.832601,31.487775;117.835266,31.487043;117.839258,31.485833;117.841393,31.485337;117.844875,31.485738;117.847852,31.486837;117.850299,31.488399;117.853268,31.489494",
                BigDecimal.ZERO.doubleValue()
        );
        System.out.println(withinArea);
    }
}
